package top.ninwoo.utils.service.impl;

import com.spotify.docker.client.messages.Container;
import com.spotify.docker.client.messages.ContainerInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import top.ninwoo.common.entity.DockerContainer;
import top.ninwoo.utils.service.ContainerStatus;
import top.ninwoo.utils.service.DockerService;
import top.ninwoo.utils.util.DockerUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class DockerServiceImpl implements DockerService, InitializingBean {
    private final Logger LOG = LoggerFactory.getLogger(DockerServiceImpl.class);

    @Autowired
    private DockerUtils dockerUtils;

    // 运行中的Docker
    private ConcurrentHashMap<String, DockerContainer> runingContainers = new ConcurrentHashMap<>();
    // 停止的Docker
    private ConcurrentHashMap<String, DockerContainer> allContainers = new ConcurrentHashMap<>();

    // 可能有线程安全问题
    @Override
    public void addNewContainerId(DockerContainer newContainer) {
        runingContainers.put(newContainer.getId(), newContainer);
        allContainers.put(newContainer.getId(), newContainer);
    }

    /**
     * 将DockerClient获取的到结果封装成为我们自定义的数据结构
     * @param containers
     * @return
     */
    public List<DockerContainer> convertDockerResult(List<Container> containers) {
        if(containers == null) {
            throw new RuntimeException("容器列表不能为null");
        }
        List<DockerContainer> dockerContainers = new ArrayList<DockerContainer>(containers.size());
        containers.forEach(c -> {
            DockerContainer container = new DockerContainer();
            container.setId(c.id());
            container.setCommand(c.command());
            container.setCreated(c.created());
            container.setPorts(c.portsAsString());
            container.setImage(c.image());
            container.setStatus(c.status());
            container.setName(c.names().get(0));
            dockerContainers.add(container);
        });
        return dockerContainers;
    }


    /**
     * 使用系统命令 docker run -itd 在后台启动一个容器,
     * 使用这种方式的一个重要原因,是因为我没搞明白docker java启动容器的api到底如何使用
     * @param container 输入一个容器的描述信息
     * @return 返回容器启动之后真实的描述信息
     */
    @Override
    public DockerContainer runDocker(DockerContainer container) {
        container = dockerUtils.runDocker(container);
        return container;
    }

    @Override
    public DockerContainer getDockerById(String id) {
        return dockerUtils.getDockerById(id);
    }

    public DockerContainer exchangeFromDockerInfo(ContainerInfo containerInfo) {
        if(containerInfo == null) {
            throw new RuntimeException("ContainerInfo cannot be null");
        }
        DockerContainer dockerContainer = new DockerContainer();
        dockerContainer.setImage(containerInfo.image());
        dockerContainer.setName(containerInfo.name());
        dockerContainer.setId(containerInfo.id());
        dockerContainer.setStatus(containerInfo.state().status());
        dockerContainer.setCreated(containerInfo.created().getTime());
        return dockerContainer;
    }

    @Override
    public String deleteDockerByName(String name) {
        String cid = dockerUtils.getDockerIdByName(name);
        if("".equals(cid)) {
            throw new RuntimeException("不存在这个容器名称[" + name + "]");
        }
        // TODO: 待测试
        dockerUtils.deleteDockerById(cid);
        return cid;
    }

    @Override
    public boolean deleteDockerById(String id) {
        return dockerUtils.deleteDockerById(id);
    }

    @Override
    public ContainerStatus getContainerStatus(String containerId) {
        // 这里查找docker容器状态可能和全量更新产生问题
        return ContainerStatus.RUNNING;
    }

    @Override
    public List<DockerContainer> getRunningContainers() {
        return new ArrayList<>(runingContainers.values());
    }

    @Override
    public int getContainersNumber(boolean isAll) {
        return isAll ? allContainers.size() : runingContainers.size();
    }

    @Override
    public boolean deleteDockerByIds(List<String> ids) {
        return false;
    }

    @Override
    public void init() {
        runingContainers.clear();
        allContainers.clear();
        List<Container> containers =
                new ArrayList<Container>();
        runingContainers.putAll(dockerUtils.getContainers(false));
        allContainers.putAll(dockerUtils.getContainers(true));

    }


    @Scheduled(fixedRate = 500)
    @Override
    public void addNewContainers() {
        LOG.debug("更新容器列表");
        Map<String, DockerContainer> containers = dockerUtils.getContainers(false);
        containers.forEach((cid, container) -> {
            if(runingContainers.containsKey(cid)) {
                // do nothing
            } else {
                // 添加到map中
                runingContainers.put(cid, container);
                // 更新allContainers
                allContainers.put(cid, container);
            }
        });
    }

    /**
     * 删除Running Map中停止的容器
     */
    @Scheduled(fixedRate = 500)
    @Override
    public void delExitedContainers() {
        runingContainers.keySet().forEach(cid -> {
            DockerContainer dockerById = dockerUtils.getDockerById(cid);
            if(dockerById == null) {
                // 容器已经被删除
                runingContainers.remove(cid);
                allContainers.remove(cid);
            } else if(dockerById.getStatus().contains("exited")) {
                runingContainers.remove(cid);
            }
        });
    }

    @Override
    public ContainerStatus checkContainerStatus(String containerId) {
        return null;
    }

    @Override
    public List<DockerContainer> getAllContainers() {
        return new ArrayList<DockerContainer>(allContainers.values());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        init();
    }

    /**
     * 是否存在该运行的容器
     * @param containerId
     * @return
     */
    @Override
    public boolean hasRunningContainer(String containerId) {
        return runingContainers.containsKey(containerId);
    }

    @Override
    public String execInDocker(String containerId, String args) {
        return execInDocker(containerId, args.split(" "));
    }

    @Override
    public String execInDocker(String containerId, String[] args) {
        // 可以对命令进行一个判断
        if(!runingContainers.containsKey(containerId)) {
            if (allContainers.containsKey(containerId)) {
                // start container!
                if(!dockerUtils.startContainer(containerId)) {
                    throw new RuntimeException("容器启动失败");
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(!runingContainers.containsKey(containerId)) {
                    throw new RuntimeException("容器不存在");
                }
            } else {
                throw new RuntimeException("容器不存在" + containerId);
            }
        }
        String result = dockerUtils.execInDocker(containerId, args);
        return result;
    }

    // 下边是基于iptables的服务接口
}
